第四個原則,不禁讓我想起前輩說,身為一個工程師,多元工作內容也是很合理的一件事。讓我們看看什麼是介面隔離原則吧。
Clients should not be forced to depend on methods that they do not use.
翻譯年糕:客戶不應該被強迫依賴他們不使用的方法。
回想當我們在公司工作時,除了寫程式、抓bug,資深一點的或許還要做簡報...等等多元
的工作內容,我們用程式來呈現我們的情況:
interface Skill{
public void coding();
public void debug();
public void prepareSlides();
}
class SeniorEngineer implements Skill{
public void coding(){
System.out.println("當碼農!!");
};
public void debug(){
System.out.println("找蟲!!");
};
public void prepareSlides(){
System.out.println("做老闆的報告!!");
};
}
public class Company {
public static void main(String args[]) {
SeniorEngineer se = new SeniorEngineer();
System.out.println("SeniorEngineer 上班");
se.coding();
se.debug();
se.debug();
}
}
output
SeniorEngineer 上班
當碼農!!
找蟲!!
做老闆的報告!!
這段程式呈現了身為一個Senior Engineer,上班需要做的工作!!但這樣存在著什麼問題呢?
假如公司今天招募了一個Junior Engineer,如下:
interface Skill{
public void coding();
public void debug();
public void prepareSlides();
}
class JuniorEngineer implements Skill{
public void coding(){
System.out.println("當碼農!!");
};
public void debug(){
System.out.println("找蟲!!");
};
public void prepareSlides(){
System.out.println("我不會做報告!!");
};
}
public class Company {
public static void main(String args[]) {
JuniorEngineer je = new JuniorEngineer();
System.out.println("SeniorEngineer 上班");
je.coding();
je.debug();
je.prepareSlides();
}
}
output
JuniorEngineer 上班
當碼農!!
找蟲!!
我不會做報告!!
剛報到的Junior Engineer,他會coding,也會debug,可是他並不會做簡報。但他一定要實作Skill介面的方法,那該怎麼辦?剛剛定義有提到,客戶不應該被強迫依賴他們不使用的方法。
顯然這個整體規劃的需要做一些更改。可能是公司招聘需求是要會做簡報的工程師,不然就是公司要把這個技能條件拆分出來。
為了讓公司的員工分工明確一點,我們把Skill分成TechSkill以及OtherSkill。
interface TechSkill{
public void coding();
public void debug();
}
interface OtherSkill{
public void prepareSlides();
}
class SeniorEngineer implements TechSkill, OtherSkill{
public void coding(){
System.out.println("當碼農!!");
};
public void debug(){
System.out.println("找蟲!!");
};
public void prepareSlides(){
System.out.println("做老闆的報告!!");
};
}
class JuniorEngineer implements TechSkill{
public void coding(){
System.out.println("當碼農!!");
};
public void debug(){
System.out.println("找蟲!!");
};
}
public class Company {
public static void main(String args[]) {
SeniorEngineer se = new SeniorEngineer();
System.out.println("SeniorEngineer work");
se.coding();
se.debug();
se.prepareSlides();
JuniorEngineer je = new JuniorEngineer();
System.out.println("JuniorEngineer work");
je.coding();
je.debug();
}
}
output
SeniorEngineer work
當碼農!!
找蟲!!
做老闆的報告!!
JuniorEngineer work
當碼農!!
找蟲!!
重新設計後,Senior和Junior所應該要會的技能已經被分類,Junior不在需要實作他不會的技能,他只需要專心的做她份內的事。未來若OtherSkill內需要增加其他工作時也不會影響JuniorEngineer的工作!!!
我們來看看UML了解一下兩者結構上的差異:
上圖表示為我們原本的設計,如果把所有的技能都放在同一個interface的話,這樣被迫class都要實作每一個技能,但並不是每個class都須要實作每個技能。所以我們把整體結構改成下圖:
可以發現,遵守ISP原則後,JuniorEngineer不再強迫要實作prepareSlides的function,他只需要做好TechSkill內的function即可。
現在我們理解在一個interface內不需要將所有的功能都包在其中,應該挑出對應的需求放入,減低interface肥大的問題,也不需要煩惱class實作不需要的function問題,減少class間的耦合性。
SRP與ISP的差異
看完這SRP與IRP兩篇的人可能會覺得,SRP跟IRP不都是拆分interface嗎?那有什麼不同?
SRP的目的在於一個模組只能有承擔一個責任。
ISP的目的在於不強迫實作的類別實作不需要的function。
我們可以用不同的角度去看這件事。
SRP注重的是設計層面,如何劃分功能的歸類,讓程式方便維護及擴充。
ISP則是注重在客戶端層面,認為只需要呈現客戶端所需要的功能即可。
ISP的目標:
1. 不要讓interface包過多的功能。
2. 不應該強迫實作沒有用到的方法。
3. 實現class間的低耦合。
範例1:SeniorEngineer
範例2:JuniorEngineer
範例3:實作ISP